# -*- coding: utf8 -*-
"""
北斗网格位置码的网格编码实现
地球表面北斗二维网格的划分原点在赤道面与本初子午面的交点处，地球表面非两级区域（南纬 88度 ~ 北纬 88度）
"""


def grid_encoding_level_10(longitude_float:float, latitude_float:float) -> str:
    """
    10级北斗网格编码
    :param longitude_float: float ; 经度精确小数表示
    :param latitude_float: float ; 纬度精确小数表示
    :return: str ; 北斗网格编码
    """
    hex_str = '0123456789ABCDE'
    # 判断一下经纬度点在南半球还是北半球
    bit_1 = 'N' if latitude_float >= 0 else 'S'
    # 一级网格剖分
    # 一级网格剖分
    grid_long_level1, grid_lat_level1 = (6 * 3600, 4 * 3600)
    grid_long_num_level1, grid_lat_num_level1 = (60, 22)
    base_long_level1 = (-180) * 3600
    base_lat_level1 = 0 * 3600 if bit_1 == 'N' else (-88) * 3600
    ## 经度
    long_quotient_level1 = (longitude_float - base_long_level1) / grid_long_level1
    long_quotient_int_level1 = int(long_quotient_level1)
    long_number_level1 = long_quotient_int_level1 + 1
    grid_long_code_str_level1 = '0{}'.format(long_number_level1) if long_number_level1 < 10 else '{}'.format(
        long_number_level1)
    ## 纬度
    lat_quotient_leve1 = (latitude_float - base_lat_level1) / grid_lat_level1
    lat_quotient_int_leve1 = int(lat_quotient_leve1)
    lat_number_level1 = lat_quotient_int_leve1 + 1
    grid_lat_code_str_level1 = chr(64 + lat_number_level1)
    # 二级网格剖分
    grid_long_level2, grid_lat_level2 = (30 * 60, 30 * 60)
    grid_long_num_level2, grid_lat_num_level2 = (12, 8)
    base_long_level2 = base_long_level1 + grid_long_level1 * long_quotient_int_level1
    base_lat_level2 = base_lat_level1 + grid_lat_level1 * lat_quotient_int_leve1
    ## 经度
    long_quotient_level2 = (longitude_float - base_long_level2) / grid_long_level2
    long_quotient_int_level2 = int(long_quotient_level2)
    ## 纬度
    lat_quotient_leve2 = (latitude_float - base_lat_level2) / grid_lat_level2
    lat_quotient_int_leve2 = int(lat_quotient_leve2)
    # 三级网格剖分
    grid_long_level3, grid_lat_level3 = (15 * 60, 10 * 60)
    grid_long_num_level3, grid_lat_num_level3 = (2, 3)
    base_long_level3 = base_long_level2 + grid_long_level2 * long_quotient_int_level2
    base_lat_level3 = base_lat_level2 + grid_lat_level2 * lat_quotient_int_leve2
    ## 经度
    long_quotient_level3 = (longitude_float - base_long_level3) / grid_long_level3
    long_quotient_int_level3 = int(long_quotient_level3)
    ## 纬度
    lat_quotient_leve3 = (latitude_float - base_lat_level3) / grid_lat_level3
    lat_quotient_int_leve3 = int(lat_quotient_leve3)
    # 四级网格剖分
    grid_long_level4, grid_lat_level4 = (1 * 60, 1 * 60)
    grid_long_num_level4, grid_lat_num_level4 = (15, 10)
    base_long_level4 = base_long_level3 + grid_long_level3 * long_quotient_int_level3
    base_lat_level4 = base_lat_level3 + grid_lat_level3 * lat_quotient_int_leve3
    ## 经度
    long_quotient_level4 = (longitude_float - base_long_level4) / grid_long_level4
    long_quotient_int_level4 = int(long_quotient_level4)
    ## 纬度
    lat_quotient_leve4 = (latitude_float - base_lat_level4) / grid_lat_level4
    lat_quotient_int_leve4 = int(lat_quotient_leve4)
    # 五级网格剖分
    grid_long_level5, grid_lat_level5 = (4, 4)
    grid_long_num_level5, grid_lat_num_level5 = (15, 15)
    base_long_level5 = base_long_level4 + grid_long_level4 * long_quotient_int_level4
    base_lat_level5 = base_lat_level4 + grid_lat_level4 * lat_quotient_int_leve4
    ## 经度
    long_quotient_level5 = (longitude_float - base_long_level5) / grid_long_level5
    long_quotient_int_level5 = int(long_quotient_level5)
    ## 纬度
    lat_quotient_leve5 = (latitude_float - base_lat_level5) / grid_lat_level5
    lat_quotient_int_leve5 = int(lat_quotient_leve5)
    # 六级网格剖分
    grid_long_level6, grid_lat_level6 = (2, 2)
    grid_long_num_level6, grid_lat_num_level6 = (2, 2)
    base_long_level6 = base_long_level5 + grid_long_level5 * long_quotient_int_level5
    base_lat_level6 = base_lat_level5 + grid_lat_level5 * lat_quotient_int_leve5
    ## 经度
    long_quotient_level6 = (longitude_float - base_long_level6) / grid_long_level6
    long_quotient_int_level6 = int(long_quotient_level6)
    ## 纬度
    lat_quotient_leve6 = (latitude_float - base_lat_level6) / grid_lat_level6
    lat_quotient_int_leve6 = int(lat_quotient_leve6)
    # 七级网格剖分
    grid_long_level7, grid_lat_level7 = (1/4, 1/4)
    grid_long_num_level7, grid_lat_num_level7 = (8, 8)
    base_long_level7 = base_long_level6 + grid_long_level6 * long_quotient_int_level6
    base_lat_level7 = base_lat_level6 + grid_lat_level6 * lat_quotient_int_leve6
    ## 经度
    long_quotient_level7 = (longitude_float - base_long_level7) / grid_long_level7
    long_quotient_int_level7 = int(long_quotient_level7)
    ## 纬度
    lat_quotient_leve7 = (latitude_float - base_lat_level7) / grid_lat_level7
    lat_quotient_int_leve7 = int(lat_quotient_leve7)
    # 八级网格剖分
    grid_long_level8, grid_lat_level8 = (1/32, 1/32)
    grid_long_num_level8, grid_lat_num_level8 = (8, 8)
    base_long_level8 = base_long_level7 + grid_long_level7 * long_quotient_int_level7
    base_lat_level8 = base_lat_level7 + grid_lat_level7 * lat_quotient_int_leve7
    ## 经度
    long_quotient_level8 = (longitude_float - base_long_level8) / grid_long_level8
    long_quotient_int_level8 = int(long_quotient_level8)
    ## 纬度
    lat_quotient_leve8 = (latitude_float - base_lat_level8) / grid_lat_level8
    lat_quotient_int_leve8 = int(lat_quotient_leve8)
    # 九级网格剖分
    grid_long_level9, grid_lat_level9 = (1/256, 1/256)
    grid_long_num_level9, grid_lat_num_level9 = (8, 8)
    base_long_level9 = base_long_level8 + grid_long_level8 * long_quotient_int_level8
    base_lat_level9 = base_lat_level8 + grid_lat_level8 * lat_quotient_int_leve8
    ## 经度
    long_quotient_level9 = (longitude_float - base_long_level9) / grid_long_level9
    long_quotient_int_level9 = int(long_quotient_level9)
    ## 纬度
    lat_quotient_leve9 = (latitude_float - base_lat_level9) / grid_lat_level9
    lat_quotient_int_leve9 = int(lat_quotient_leve9)
    # 十级网格剖分
    grid_long_level10, grid_lat_level10 = (1/2048, 1/2048)
    grid_long_num_level10, grid_lat_num_level10 = (8, 8)
    base_long_level10 = base_long_level9 + grid_long_level9 * long_quotient_int_level9
    base_lat_level10 = base_lat_level9 + grid_lat_level9 * lat_quotient_int_leve9
    ## 经度
    long_quotient_level10 = (longitude_float - base_long_level10) / grid_long_level10
    long_quotient_int_level10 = int(long_quotient_level10)
    ## 纬度
    lat_quotient_leve10 = (latitude_float - base_lat_level10) / grid_lat_level10
    lat_quotient_int_leve10 = int(lat_quotient_leve10)
    # 分区域处理
    if longitude_float >= 0 and latitude_float >= 0:
        # 二级
        long_number_level2 = long_quotient_int_level2
        lat_number_level2 = lat_quotient_int_leve2
        # 三级
        long_number_level3 = long_quotient_int_level3
        lat_number_level3 = lat_quotient_int_leve3
        # 四级
        long_number_level4 = long_quotient_int_level4
        lat_number_level4 = lat_quotient_int_leve4
        # 五级
        long_number_level5 = long_quotient_int_level5
        lat_number_level5 = lat_quotient_int_leve5
        # 六级
        long_number_level6 = long_quotient_int_level6
        lat_number_level6 = lat_quotient_int_leve6
        # 七级
        long_number_level7 = long_quotient_int_level7
        lat_number_level7 = lat_quotient_int_leve7
        # 八级
        long_number_level8 = long_quotient_int_level8
        lat_number_level8 = lat_quotient_int_leve8
        # 九级
        long_number_level9 = long_quotient_int_level9
        lat_number_level9 = lat_quotient_int_leve9
        # 十级
        long_number_level10 = long_quotient_int_level10
        lat_number_level10 = lat_quotient_int_leve10
    elif longitude_float < 0 and latitude_float >= 0:
        # 二级
        long_number_level2 = grid_long_num_level2 - long_quotient_int_level2 - 1
        lat_number_level2 = lat_quotient_int_leve2
        # 三级
        long_number_level3 = grid_long_num_level3 - long_quotient_int_level3 - 1
        lat_number_level3 = lat_quotient_int_leve3
        # 四级
        long_number_level4 = grid_long_num_level4 - long_quotient_int_level4 - 1
        lat_number_level4 = lat_quotient_int_leve4
        # 五级
        long_number_level5 = grid_long_num_level5 - long_quotient_int_level5 - 1
        lat_number_level5 = lat_quotient_int_leve5
        # 六级
        long_number_level6 = grid_long_num_level6 - long_quotient_int_level6 - 1
        lat_number_level6 = lat_quotient_int_leve6
        # 七级
        long_number_level7 = grid_long_num_level7 - long_quotient_int_level7 - 1
        lat_number_level7 = lat_quotient_int_leve7
        # 八级
        long_number_level8 = grid_long_num_level8 - long_quotient_int_level8 - 1
        lat_number_level8 = lat_quotient_int_leve8
        # 九级
        long_number_level9 = grid_long_num_level9 - long_quotient_int_level9 - 1
        lat_number_level9 = lat_quotient_int_leve9
        # 十级
        long_number_level10 = grid_long_num_level10 - long_quotient_int_level10 - 1
        lat_number_level10 = lat_quotient_int_leve10
    elif longitude_float >= 0 and latitude_float < 0:
        # 二级
        long_number_level2 = long_quotient_int_level2
        lat_number_level2 = grid_lat_num_level2 - lat_quotient_int_leve2 - 1
        # 三级
        long_number_level3 = long_quotient_int_level3
        lat_number_level3 = grid_lat_num_level3 - lat_quotient_int_leve3 - 1
        # 四级
        long_number_level4 = long_quotient_int_level4
        lat_number_level4 = grid_lat_num_level4 - lat_quotient_int_leve4 - 1
        # 五级
        long_number_level5 = long_quotient_int_level5
        lat_number_level5 = grid_lat_num_level5 - lat_quotient_int_leve5 - 1
        # 六级
        long_number_level6 = long_quotient_int_level6
        lat_number_level6 = grid_lat_num_level6 - lat_quotient_int_leve6 - 1
        # 七级
        long_number_level7 = long_quotient_int_level7
        lat_number_level7 = grid_lat_num_level7 - lat_quotient_int_leve7 - 1
        # 八级
        long_number_level8 = long_quotient_int_level8
        lat_number_level8 = grid_lat_num_level8 - lat_quotient_int_leve8 - 1
        # 九级
        long_number_level9 = long_quotient_int_level9
        lat_number_level9 = grid_lat_num_level9 - lat_quotient_int_leve9 - 1
        # 十级
        long_number_level10 = long_quotient_int_level10
        lat_number_level10 = grid_lat_num_level10 - lat_quotient_int_leve10 - 1
    elif longitude_float < 0 and latitude_float < 0:
        # 二级
        long_number_level2 = grid_long_num_level2 - long_quotient_int_level2 - 1
        lat_number_level2 = grid_lat_num_level2 - lat_quotient_int_leve2 - 1
        # 三级
        long_number_level3 = grid_long_num_level3 - long_quotient_int_level3 - 1
        lat_number_level3 = grid_lat_num_level3 - lat_quotient_int_leve3 - 1
        # 四级
        long_number_level4 = grid_long_num_level4 - long_quotient_int_level4 - 1
        lat_number_level4 = grid_lat_num_level4 - lat_quotient_int_leve4 - 1
        # 五级
        long_number_level5 = grid_long_num_level5 - long_quotient_int_level5 - 1
        lat_number_level5 = grid_lat_num_level5 - lat_quotient_int_leve5 - 1
        # 六级
        long_number_level6 = grid_long_num_level6 - long_quotient_int_level6 - 1
        lat_number_level6 = grid_lat_num_level6 - lat_quotient_int_leve6 - 1
        # 七级
        long_number_level7 = grid_long_num_level7 - long_quotient_int_level7 - 1
        lat_number_level7 = grid_lat_num_level7 - lat_quotient_int_leve7 - 1
        # 八级
        long_number_level8 = grid_long_num_level8 - long_quotient_int_level8 - 1
        lat_number_level8 = grid_lat_num_level8 - lat_quotient_int_leve8 - 1
        # 九级
        long_number_level9 = grid_long_num_level9 - long_quotient_int_level9 - 1
        lat_number_level9 = grid_lat_num_level9 - lat_quotient_int_leve9 - 1
        # 十级
        long_number_level10 = grid_long_num_level10 - long_quotient_int_level10 - 1
        lat_number_level10 = grid_lat_num_level10 - lat_quotient_int_leve10 - 1
    else:
        raise Exception('error')
    bit_2_3 = grid_long_code_str_level1
    bit_4 = grid_lat_code_str_level1
    bit_5 = hex_str[long_number_level2]
    bit_6 = hex_str[lat_number_level2]
    bit_7 = long_number_level3 + lat_number_level3 * grid_long_num_level3
    bit_8 = hex_str[long_number_level4]
    bit_9 = hex_str[lat_number_level4]
    bit_10 = hex_str[long_number_level5]
    bit_11 = hex_str[lat_number_level5]
    bit_12 = long_number_level6 + lat_number_level6 * grid_long_num_level6
    bit_13 = hex_str[long_number_level7]
    bit_14 = hex_str[lat_number_level7]
    bit_15 = hex_str[long_number_level8]
    bit_16 = hex_str[lat_number_level8]
    bit_17 = hex_str[long_number_level9]
    bit_18 = hex_str[lat_number_level9]
    bit_19 = hex_str[long_number_level10]
    bit_20 = hex_str[lat_number_level10]
    grid_code = f'{bit_1}{bit_2_3}{bit_4}{bit_5}{bit_6}{bit_7}{bit_8}{bit_9}{bit_10}{bit_11}{bit_12}{bit_13}{bit_14}{bit_15}{bit_16}{bit_17}{bit_18}{bit_19}{bit_20}'
    return grid_code


if __name__ == '__main__':
    # 经度 - x 轴 东经
    longitude = 'E116°18′45.37″'
    # 维度 - y 轴 北半球
    latitude = 'N39°59′35.38″'
    # 转化为数值
    from util_tool import transform_longitude_or_latitude_into_float
    longitude_float = transform_longitude_or_latitude_into_float(longitude)
    latitude_float = transform_longitude_or_latitude_into_float(latitude)
    print(f'longitude --{longitude} -- transform into --{longitude_float}--.')
    print(f'latitude --{latitude} -- transform into --{latitude_float}--.')
    print(grid_encoding_level_10(longitude_float, latitude_float))
    # 性能测试
    from timeit import timeit
    iter_number = 1000
    duration = timeit(lambda: grid_encoding_level_10(longitude_float, latitude_float), number=iter_number)
    print('generate grid code,iter number {},cost time is {} seconds'.format(iter_number, duration))
    # generate grid code,iter number 1000,cost time is 0.08302429999457672 seconds